#ifndef _COMM_HPP__
#define _COMM_HPP__

#include <iostream>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <cassert>
#include <unistd.h>
#include <sys/stat.h>

using namespace std;


#define PATHNAME "."
#define PROJ_ID 0x6571
//#define PROJ_ID 0x6666
#define SERVER 1
#define CLIENT 0
const int gsize = 4096;

// key_t getKey(){
//     key_t key = ftok(PATHNAME, PROJ_ID);
//     if(key == -1){
//         cerr << errno << " : " << strerror(errno) << endl;
//         exit(1);
//     }
//     return key;
// }

// string toHex(int x){
//     char buffer[64];
//     snprintf(buffer, sizeof(buffer), "0x%x", x);
//     return buffer;
// }

// // int createSHM(key_t key, int size){
// //     int shmid = shmget(key, gsize, IPC_CREAT | IPC_EXCL);
// //     if(shmid == -1){
// //         cerr << errno << " : " << strerror(errno) << endl;
// //         cout << "IPC已存在" << endl;
// //         exit(2);
// //     }
// //     return shmid;
// // }

// // int getSHM(key_t key, int size){
// //     int shmid = shmget(key, gsize, IPC_CREAT);
// //     return shmid;
// // }

// static int createShmHelper(key_t key, int size, int flag){
//     int shmid = shmget(key, gsize, flag);
//     if(shmid == -1){
//         cerr << errno << " : " << strerror(errno) << endl;
//         cout << "IPC已存在" << endl;
//         exit(2);
//     }
//     return shmid;
// }

// int createShm(key_t key, int size){
//     umask(0);
//     return createShmHelper(key, size, IPC_CREAT | IPC_EXCL | 0666);
// }

// int getShm(key_t key, int size){
//     return createShmHelper(key, size, IPC_CREAT);
// }

// void delShm(int shmid){
//     int n = shmctl(shmid, IPC_RMID, nullptr);
//     if(n == -1){
//         cerr << errno << " : " << strerror(errno) << endl;
//         cout << "delShm error" << endl;
//         exit(3);
//     }
// }

// char* attachShm(int shmid){
//     char *start = (char*)shmat(shmid, nullptr, 0);
//     return start;
// }

// void detachShm(char* start){
//     int n = shmdt(start);
//     if(n == -1){
//         cerr << errno << " : " << strerror(errno) << endl;
//         cout << "deltchShm error" << endl;
//         exit(4);
//     }
// }

class Shm{
public:
    Shm(int type)
        :_type(type){
        //1.创建key
        key_t key = getKey();

        //2.创建/获取共享内存
        if(_type==SERVER){
            _shmid = createShm(key, gsize);
            cout << "创建共享内存" << endl;
        }
        else{
            _shmid = getShm(key, gsize);
            cout << "获取共享内存" << endl;
        }

        //3.关联
        _start = attachShm(_shmid);
    }

    ~Shm(){
        //4.取消关联
        detachShm(_start);

        if(_type == SERVER){
            //5.删除共享内存
            delShm(_shmid);
            cout << "删除共享内存" << endl;
        }
    }

    key_t getKey(){
        key_t key = ftok(PATHNAME, PROJ_ID);
        if(key == -1){
            cerr << errno << " : " << strerror(errno) << endl;
            exit(1);
        }
        return key;
    }

    string toHex(int x){
        char buffer[64];
        snprintf(buffer, sizeof(buffer), "0x%x", x);
        return buffer;
    }

    static int createShmHelper(key_t key, int size, int flag){
        int shmid = shmget(key, gsize, flag);
        if(shmid == -1){
            cerr << errno << " : " << strerror(errno) << endl;
            cout << "IPC已存在" << endl;
            exit(2);
        }
        return shmid;
    }

    int createShm(key_t key, int size){
        umask(0);
        cout << "createShm" << endl;
        return createShmHelper(key, size, IPC_CREAT | IPC_EXCL | 0666);
    }

    int getShm(key_t key, int size){
        cout << "getShm" << endl;
        return createShmHelper(key, size, IPC_CREAT);
    }

    void delShm(int shmid){
        int n = shmctl(shmid, IPC_RMID, nullptr);
        if(n == -1){
            cerr << errno << " : " << strerror(errno) << endl;
            cout << "delShm error" << endl;
            exit(3);
        }
        cout << "delShm" << endl;
    }

    char* attachShm(int shmid){
        char *start = (char*)shmat(shmid, nullptr, 0);
        return start;
    }

    void detachShm(char* start){
        int n = shmdt(start);
        if(n == -1){
            cerr << errno << " : " << strerror(errno) << endl;
            cout << "detachShm error" << endl;
            exit(4);
        }
    }

    char* getStart(){
        return _start;
    }

private:
    char* _start;
    int _type;
    int _shmid;
};

#endif
